package org.lambdateacher.gwt.server;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.lambdateacher.gwt.client.LambdaService;
import org.lambdateacher.gwt.shared.ReduceResponse;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import edu.lambdateacher.InterpreterFacade;
import edu.lambdateacher.InterpreterResponseBean;
import edu.lambdateacher.PropertiesManager;
import edu.lambdateacher.ReductionResponseBean;
import edu.lambdateacher.expressions.Expression;
import edu.lambdateacher.parser.ParseException;

/**
 * The server-side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class LambdaServiceImpl extends RemoteServiceServlet implements LambdaService {
	
	private final static Logger log = Logger.getLogger(LambdaServiceImpl.class);

	private InterpreterFacade interpreterFacade = new InterpreterFacade();

	public String evaluateExpression(String input) throws IllegalArgumentException {
		InterpreterResponseBean response;
		try {
			response = interpreterFacade.enterExpression(input);
		} catch (ParseException e) {
			log.error(e.getMessage());
			String errorString = "Parse error";
			return errorString;
		}
		String responseString = escapeHtml(response.getExpressionToDisplay());
		saveInSession(response.getExpression());

		return responseString;
	}

	/**
	 * Escape an html string. Escaping data received from the client helps to
	 * prevent cross-site script vulnerabilities.
	 * 
	 * @param html
	 *            the html string to escape
	 * @return the escaped string
	 */
	private String escapeHtml(String html) {
		if (html == null) {
			return null;
		}
		return html.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
	}

	@Override
	public ReduceResponse reduce(String input) {
		Expression expression = getFromSession();
		
		if(expression == null){
			evaluateExpression(input);
			expression = getFromSession();
		}
		
		ReductionResponseBean reductionResponseBean = interpreterFacade.reduce(expression,PropertiesManager.MAX_REDUCTIONS);
		ReduceResponse reduceResponse = new ReduceResponse();
		reduceResponse.setExplanation(reductionResponseBean.getExplanation().replaceAll("\n", "<br/>"));
		reduceResponse.setIntermediateExpressions(reductionResponseBean.getIntermediateExpressions());
		reduceResponse.setLambdaString(reductionResponseBean.getLambdaString());
		return reduceResponse;
	}

	private void saveInSession(Expression expression) {
		HttpServletRequest request = this.getThreadLocalRequest();
		HttpSession session = request.getSession();
		session.setAttribute("Expression", expression);
	}
	
	private Expression getFromSession(){
		HttpServletRequest request = this.getThreadLocalRequest();
		HttpSession session = request.getSession();
		return (Expression) session.getAttribute("Expression");
	}
}
